package com.mdms.hibernate;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.time.DateUtils;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;

import com.mdms.commands.user.ClientContext;
import com.mdms.interfaces.orm.CrudDAO;

public class CrudDaoHibernate implements CrudDAO {

	private Class persistentClass;

	private Session minevraSession;

	private Session mDMSSession;
	
	private ClientContext clientContext;
	
	public ClientContext getClientContext() {
		return clientContext;
	}

	public void setClientContext(ClientContext clientContext) {
		this.clientContext = clientContext;
	}

	private static final Pattern CREATE_DATE_GETTER_PATTERN = Pattern.compile("get..._audit_cd");
	
	private static final Pattern MODIFY_DATE_SETTER_PATTERN = Pattern.compile("set..._audit_md");
	
	private static final Pattern MODIFY_DATE_GETTER_PATTERN = Pattern.compile("get..._audit_md");

	/**
	 * Pocz�tek prefixu w nazwie metody np. get..._audit_cd, gdzie ... to
	 * prefix
	 */
	private static final int PREFIX_BEGIN_INDEX = 3;

	/**
	 * Koniec prefixu w nazwie metody np. get..._audit_cd, gdzie ... to prefix
	 */
	private static final int PREFIX_END_INDEX = 6;
	
	private static Pattern pattern = Pattern.compile("get([A-z]){3}_id");

	public CrudDaoHibernate() {
	}

	public CrudDaoHibernate(Class persistentClass) {
		this.persistentClass = persistentClass;
	}

	public void setMinevraSession(Session s) {
		this.minevraSession = s;
	}

	
	public void setmDMSSession(Session mDMSSession) {
		this.mDMSSession = mDMSSession;
	}

	protected Session getSession() {
		if (persistentClass == null) {
			//throw new Exception("This operation requires setting persistenceClass");
		}

		try {
			if (getSimpleClassName(persistentClass).toLowerCase().startsWith("udt")) {

				if (minevraSession == null) {
					minevraSession = HibernateUtils.getSessionFactory(HibernateUtils.MINVEVRA_KEY).getCurrentSession();
					if (!minevraSession.isOpen()){
						minevraSession = HibernateUtils.getSessionFactory(HibernateUtils.MINVEVRA_KEY).openSession();
					}
					
					minevraSession.setFlushMode(org.hibernate.FlushMode.COMMIT);
				}
				return minevraSession;
			} else {
				if (mDMSSession == null) {
					mDMSSession = HibernateUtils.getSessionFactory(HibernateUtils.MDMS_KEY).getCurrentSession();
					if (!mDMSSession.isOpen()){
						mDMSSession = HibernateUtils.getSessionFactory(HibernateUtils.MDMS_KEY).openSession();
					}
					mDMSSession.setFlushMode(org.hibernate.FlushMode.COMMIT);
				}
				return mDMSSession;
			}
		} catch (Throwable t) {
			throw new RuntimeException(t);
		}

	}

	public Class getPersistentClass()  {
		if (persistentClass == null) {
			//throw new Exception("This operation requires setting persistenceClass");
		}
		return persistentClass;
	}

	public void setPersistentClass(Class persistentClass) {
		this.persistentClass = persistentClass;
	}


	public Object findById(Long id)  {
		Object entity = getSession().load(getPersistentClass(), id);
		return entity;
	}

	public Object findForUpdateById(Long id) {
		Object entity = getSession().load(getPersistentClass(), id, LockMode.UPGRADE);
		return entity;
	}

	public Object find(Object entity, boolean checkAuditMD) {
		this.persistentClass = Hibernate.getClass(entity);
		if (checkAuditMD) {
			if (!checkAuditDate(entity)) {
				//throw new Exception("Data was modified by another user!");
			}
		}

		String prefix = getPrefixForDto(entity.getClass());
		try {
			Method method = entity.getClass().getMethod("get" + prefix + "_id", new Class[0]);
			Long id = (Long) method.invoke(entity, new Object[0]);
			entity = getSession().load(Hibernate.getClass(entity), id);
		} catch (Exception e) {
			throw new RuntimeException("Error getting records", e);
		}

		return entity;
	}


	/**
	 * Metoda lockuje obiekt ; sprawdza czy obiekt nie jest lockowany przez innego uzytkownika;
	 * ignoruje lockowanie przez uzytkownika podanego w usrID 
	* @param entity - obiekt do zalockowania
	* @param usrId - zalogowany uzytkownik
	* @return
	* @see com.comarch.ccpm.core.interfaces.orm.dao.CrudDAO#findAndLock(java.lang.Object, java.lang.String)
	 */
	public Object findAndLock(Object entity, String usrId) {
		String prefix = getPrefixForDto(entity.getClass());

		try {
			Method method = entity.getClass().getMethod("get" + prefix + "_id", new Class[0]);
			entity = findById((Long) method.invoke(entity, new Object[0]));
			Method getmethod = entity.getClass().getMethod(
					"get" + prefix, new Class[0]);
			String mc_state = (String) getmethod.invoke(entity, new Object[0]);
			
			Method getmethod2 = entity.getClass().getMethod(
					"get" + prefix + "_" + "AuditMu", new Class[0]);
			String audit_mu = ((Long)getmethod2.invoke(entity, new Object[0])).toString();
			

			if (!audit_mu.equals(usrId)) {
				//throw new Exception("Choosen record is in modification by another user!");
			}
		} catch (SecurityException e) {
			throw new RuntimeException("Get and lock record ERROR!",e);
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			throw new RuntimeException("Get and lock record ERROR!",e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException("Get and lock record ERROR!",e);
		} catch (InvocationTargetException e) {
			throw new RuntimeException("Get and lock record ERROR!",e);
		}

		return entity;
	}
	
	

	public Object unLock(Object entity) {
		String prefix = getPrefixForDto(entity.getClass());
		try {
			Method method = entity.getClass().getMethod("get" + prefix + "_id", new Class[0]);
			setPersistentClass(Hibernate.getClass(entity));
			unLockById((Long) method.invoke(entity, new Object[0]));
			return entity;
		} catch (Exception e) {
			throw new RuntimeException("Unlock record ERROR", e);
		}
	}


	public List findAll() {
		return findByCriterions(new ArrayList());
	}

	public List findByExample(Object exampleInstance, List excludeProperties) {
		this.persistentClass = Hibernate.getClass(exampleInstance);
		Criteria crit = getSession().createCriteria(persistentClass);
		Example example = Example.create(exampleInstance);
		for (Iterator iter = excludeProperties.iterator(); iter.hasNext();) {
			String exclude = (String) iter.next();
			example.excludeProperty(exclude);
		}
		crit.add(example);
		return crit.list();
	}

	public Object makePersistent(Object entity) {
		this.persistentClass = Hibernate.getClass(entity);
		if (!checkAuditDate(entity)) {
			//throw new Exception("Data was modified by another user!");
		}
		setAuditDates(entity);
		getSession().saveOrUpdate(entity);
		return entity;
	}

	
	/* (non-Javadoc)
	 * KZI Dokladam metode ktora umozliwi zapis obiektu bez sprawdzenia audit_date
	 * sa obiekty ktore nie maja audit_date i jest problem z ich zapisaniem
	 * @see com.comarch.ccpm.core.interfaces.orm.dao.CrudDAO#merge(java.lang.Object)
	 */
	public Object merge(Object entity) {
		return merge(entity, true, true);
	}

	public Object merge(Object entity, boolean hasAuditDates) {
		return merge(entity, hasAuditDates, true);
	}
	
	/**
	 * @param entity obiekt do zapisania
	 * @param hasAuditDates czy obiekt zawiera pola audytowe
	 * @param hasPkLongType czy obiekt zawiera primary key typu java.lang.Long
	 */
	public Object merge(Object entity, boolean hasAuditDates, boolean hasPkLongType) {
		
		try{
		this.persistentClass = Hibernate.getClass(entity);
		
		if (hasAuditDates && !checkAuditDate(entity)) {
			//throw new Exception("Data was modified by another user!");
		}
		if(hasAuditDates) {
			setAuditDates(entity);
		}
		Transaction tx = getSession().beginTransaction();
		//KU dodano obsluge klas, dla ktorych id jest java.lang.String zamiast java.lang.Long
		if ((hasPkLongType && getDtoPK(entity) == null) || !hasPkLongType) {
			getSession().saveOrUpdate(entity);
		} else {
			entity = getSession().merge(entity);
			tx.commit();
		}
		
		//KU jezeli jest to standardowy obiekt CBPM/CCPM (id jest typu Long) to przeprowadzamy sprawdzenie
		//w przeciwnym wypadku pomijamy kwestie sprawdzania (nie musimy dbac o spojnosc)
		if(hasPkLongType) {
			try {
				setPersistentClass(Hibernate.getClass(entity));
				String prefix = getPrefixForDto(entity.getClass());
				Method method = entity.getClass().getMethod("get" + prefix + "_id", new Class[0]);
				entity = findById((Long) method.invoke(entity, new Object[0]));
				tx.commit();
			} catch (Exception e) {
				throw new RuntimeException("Store record ERROR",e);
			}
		}
		}catch(Exception e){
			String test="";
		}

		return entity;
	}

	public void makeTransient(Object entity) {
		this.persistentClass = Hibernate.getClass(entity);
		getSession().delete(entity);
	}

	public void flush() {
		getSession().flush();
	}

	public void clear() {
		getSession().clear();
	}

	/**
	 * @see findByCriteria(List criterion, int firstResult, int pageSize, String
	 *      order, boolean asc)
	 */
	public List findByCriterions(List criterion) {
		return findByCriterions(criterion, 0, 0, null, true);
	}

	/**
	 * @see findByCriteria(List criterion, int firstResult, int pageSize, String
	 *      order, boolean asc)
	 */
	public List findByCriterions(List criterion, int firstResult, int pageSize) {
		return findByCriterions(criterion, firstResult, pageSize, null, true);
	}

	/**
	 * Wyszukiwanie wg. zadanych kryteri�w (podanych jako lista obiekt�w)
	 * 
	 * Niezbyt eleganckie rozwiazanie... :/ Ale inne API niz Hibernate nie
	 * obluguja Criteria, wiec tak musi byc dla zachowania ogolnosci
	 */
	public List findByCriterions(List criterion, int firstResult, int pageSize, String order, boolean asc) {
		//Transaction tx= getSession().beginTransaction();
		Criteria crit = getSession().createCriteria(getPersistentClass());
		for (Iterator iter = criterion.iterator(); iter.hasNext();) {
			Criterion c = (Criterion) iter.next();
			crit.add(c);
		}
		// stronicowanie
		if (pageSize > 0) {
			crit.setFirstResult(firstResult);
			crit.setMaxResults(pageSize);
		}
		// sortowanie
		if (order != null && order.length() > 0) {
			if (asc) {
				crit.addOrder(Order.asc(order));
			} else {
				crit.addOrder(Order.desc(order));
			}
		}
		List temp = crit.list();
		//tx.commit();
		//getSession().clear();
		return temp;
	}

	/**
	 * Pobiera liczb� rekord�w spe�niaj�cych zadane kryteria
	 */
	public int getResultSetSize(List criterion) {
		Criteria crit = getSession().createCriteria(getPersistentClass());
		crit.setProjection(Projections.rowCount());
		for (Iterator iter = criterion.iterator(); iter.hasNext();) {
			Criterion c = (Criterion) iter.next();
			crit.add(c);
		}
		Number numberOfRecords = ((Number) crit.uniqueResult());

		if (numberOfRecords == null) {
			return 0;
		} else {
			return numberOfRecords.intValue();
		}
	}
	
	public Transaction beginTransaction(){
		return getSession().beginTransaction();
	}

	/**
	 * Pobiera liczb� rekord�w spe�niaj�cych zadane kryteria
	 */
	public int getResultSetSize(Object criteria) {
		DetachedCriteria detachedCriteria = (DetachedCriteria) criteria;
		Criteria crit = detachedCriteria.getExecutableCriteria(getSession());
		crit.setProjection(Projections.rowCount());
		crit.setFirstResult(0); // bez tego ani rusz :>
		// TODO zamiast powyzszego pomyslec nad zmiana RootTransformer'a - moze
		// cos da
		Number numberOfRecords = ((Number) crit.uniqueResult());
		if (numberOfRecords == null) {
			return 0;
		} else {
			return numberOfRecords.intValue();
		}
	}
	
	

	/**
	 * Pobiera liczbe rekord�w z uwzglednieniem distinct
	 */
	public int getDistinctResultSetSize(Object criteria) {
		DetachedCriteria detachedCriteria = (DetachedCriteria) criteria;
		Criteria crit = detachedCriteria.getExecutableCriteria(getSession());
		//klucz g�owny tabeli
		String primaryKey=
			getSession().getSessionFactory().getClassMetadata(persistentClass).getIdentifierPropertyName();
		crit.setProjection(Projections.countDistinct(primaryKey));
		crit.setFirstResult(0);
		Number numberOfRecords = ((Number) crit.uniqueResult());
		if (numberOfRecords == null) {
			return 0;
		} else {
			return numberOfRecords.intValue();
		}
	}

	/**
	 * Pobiera liczb� rekord�w spe�niaj�cych zadane kryteria
	 * 
	 * @param criteria
	 *            obiekt typu DetachedCriteria
	 * @return
	 * @see com.comarch.ccpm.core.interfaces.orm.dao.CrudDAO#findByCriteria(java.lang.Object)
	 */
	public List findByCriteria(Object criteria) {
		DetachedCriteria detachedCriteria = (DetachedCriteria) criteria;
		Criteria crit = detachedCriteria.getExecutableCriteria(getSession());
		return crit.list();
	}

	/**
	 * Pobiera liczb� rekord�w spe�niaj�cych zadane kryteria, dziel�c dane na
	 * strony zawieraj�ce <i>pageSize</i> rekord�w pocz�wszy od <i>firstResult</i>
	 * 
	 * @param criteria
	 *            obiekt typu DetachedCriteria
	 * @param firstResult
	 *            od kt�rego rekordu zaczyna sie pobrana lista
	 * @param pageSize
	 *            ile rekord�w ma by� na li�cie
	 * @return
	 * @see com.comarch.ccpm.core.interfaces.orm.dao.CrudDAO#findByCriteria(java.lang.Object)
	 */
	public List findByCriteria(Object criteria, int firstResult, int pageSize) {
		DetachedCriteria detachedCriteria = (DetachedCriteria) criteria;
		Criteria crit = detachedCriteria.getExecutableCriteria(getSession());
		crit.setFirstResult(firstResult);
		if (pageSize > 0) {
			crit.setMaxResults(pageSize);
		}
		return crit.list();
	}
	
	/**
	 * Pobiera liczb� rekord�w przy uzyciu select distinct
	 * spe�niaj�cych zadane kryteria, dziel�c dane na
	 * strony zawieraj�ce <i>pageSize</i> rekord�w pocz�wszy od <i>firstResult</i>
	 * 
	 * @param criteria
	 *            obiekt typu DetachedCriteria
	 * @param firstResult
	 *            od kt�rego rekordu zaczyna sie pobrana lista
	 * @param pageSize
	 *            ile rekord�w ma by� na li�cie
	 * @return
	 * @see com.comarch.ccpm.core.interfaces.orm.dao.CrudDAO#findByCriteriaDistinct(java.lang.Object)
	 */
	public List findByCriteriaDistinct(Object criteria, int firstResult, int pageSize) {
		DetachedCriteria detachedCriteria = (DetachedCriteria) criteria;
		Criteria crit = detachedCriteria.getExecutableCriteria(getSession());
		crit.setFirstResult(firstResult);
		crit.setProjection(Projections.distinct(formProjection(persistentClass)));
		if (pageSize > 0) {
			crit.setMaxResults(pageSize);
		}
		List resultList = crit.list();
		crit.setProjection(null);
		crit.setResultTransformer(null);
		return resultList;
	}
	
	
	/**
	 * tworzy liste projekcji
	 * @param properties
	 * @return
	 */
	public Projection formProjection(Class findClass) {
		String[] properties = getSession().getSessionFactory().getClassMetadata(findClass).getPropertyNames();
		String id = getSession().getSessionFactory().getClassMetadata(findClass).getIdentifierPropertyName();
		String prefix = "alias_"; 
        ProjectionList list = Projections.projectionList();
        list.add(Projections.property(id), prefix+id);
        for (int i = 0; i < properties.length; ++i){
            list.add(Projections.property(properties[i]), prefix+properties[i]);
        }
        return list;
	}

	/**
	 * Ustawia uzytkownika/daty audytowe podanego obiektu
	 * 
	 * @param entity -
	 *            obiekt, w ktorym maja by� sprawdzone pola CD, CU, MD, MU
	 */
	public void setAuditDates(Object entity) {

		/** Id uzytkownika wykonujacego dodanie/modyfikacje z commandContext'u */
		Long userId;
		try {
			userId = Long.valueOf(clientContext.getUsr_id());
		} catch (RuntimeException e) {
			userId = new Long(0);
		}

		boolean isNew = false;

		Method[] methods = entity.getClass().getMethods();
		for (int i = 0; i < methods.length; i++) {

			/*--------------------- *
			 * Utworzenie rekordu	*
			 *----------------------*/
			Matcher cMatcher = CREATE_DATE_GETTER_PATTERN.matcher(methods[i].getName());
			if (cMatcher.matches()) {
				try {
					Date audit_cd = (Date) methods[i].invoke(entity, new Object[0]);
					if (audit_cd == null) {
						isNew = true;
						String prefix = methods[i].getName().substring(PREFIX_BEGIN_INDEX, PREFIX_END_INDEX);
						// AUDIT_CD
						Class[] classtablecd = { Date.class };
						//JM: obcinam date audytowa do sekund (taka dokladnosc jest na bazie)
						//zeby przy ponownym zapisie tego obiektu nie lecial ConcurrentModificationException
						Object[] argtablecd = { DateUtils.truncate(new Date(),Calendar.SECOND) };
						Method datesetter = entity.getClass().getMethod("set" + prefix + "_audit_cd", classtablecd);
						datesetter.invoke(entity, argtablecd);
						// AUDIT_CU
						Class[] classtablecu = { Long.class };
						Object[] argtablecu = { userId };
						Method usersetter = entity.getClass().getMethod("set" + prefix + "_audit_cu", classtablecu);
						usersetter.invoke(entity, argtablecu);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}

			/*--------------------- *
			 * Modyfikacja rekordu	*
			 *----------------------*/
			Matcher mMatcher = MODIFY_DATE_SETTER_PATTERN.matcher(methods[i].getName());
			if (mMatcher.matches()) {

				try {
					String prefix = methods[i].getName().substring(PREFIX_BEGIN_INDEX, PREFIX_END_INDEX);
					// AUDIT_MD
					//JM: obcinam date audytowa do sekund (taka dokladnosc jest na bazie)
					//zeby przy ponownym zapisie tego obiektu nie lecial ConcurrentModificationException
					Object[] argtablecd = { DateUtils.truncate(new Date(),Calendar.SECOND) };
					Method datesetter = methods[i];
					// AUDIT_MU
					Class[] classtablecu = { Long.class };
					Object[] argtablecu = { userId };
					Method usersetter = entity.getClass().getMethod("set" + prefix + "_audit_mu", classtablecu);
					if (!isNew) {
						datesetter.invoke(entity, argtablecd);
						usersetter.invoke(entity, argtablecu);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}

			/*--------------------------------- *
			 * Sprawdzenie kolekcji podrzednych	*
			 *----------------------------------*/
			if (methods[i].getName().startsWith("get") 
					&&	Collection.class.isAssignableFrom(methods[i].getReturnType())) {

				try {
					Object subobject = methods[i].invoke(entity, new Object[0]);
					if (subobject instanceof Collection && Hibernate.isInitialized(subobject)) {
						Collection collection = (Collection) subobject;
						for (Iterator iter = collection.iterator(); iter.hasNext();) {
							Object collectionElement = iter.next();
							setAuditDates(collectionElement);
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}

			}

		}

	}

	/**
	 * Metoda por�wnuje daty audytowe obiektu, kt�ry jest w bazie i tego,
	 * kt�rego chcemy zapisa� - je�eli s� r�ne, zg�asza wyj�tek (tak si� mo�e
	 * zdarzy�, gdy u�ytkownik d�ugo edytuje dane, tryb edycji zosta� wy��czony
	 * przez job'a na bazie i inny u�ytkownik zd��y� ju� ten rekord zmieni�)
	 * 
	 * @param entity
	 * @return true je�li OK, false je�li daty s� r�nes
	 */
	public boolean checkAuditDate(Object entity) {

		Method[] methods = entity.getClass().getMethods();

		Method dategetter = null;
		Long id = null;

		Date dbDate = null;
		Date newDate = null;

		boolean result = false;

		for (int i = 0; i < methods.length; i++) {

			/*--------------------------------*
			 *  Pobranie metod i id z obiektu *
			 *--------------------------------*/
			Matcher mMatcher = MODIFY_DATE_GETTER_PATTERN.matcher(methods[i].getName());
			if (mMatcher.matches()) {

				try {
					String prefix = methods[i].getName().substring(PREFIX_BEGIN_INDEX, PREFIX_END_INDEX);
					// AUDIT_MD
					dategetter = methods[i];
					// ID
					id = (Long) entity.getClass().getMethod("get" + prefix + "_id", new Class[0]).invoke(entity,
							new Object[0]);

					// nowy obiekt
					if (id == null) {
						return true;
					}

				} catch (Exception e) {
					e.printStackTrace();
				}

				/*---------------------------*
				 * Dane rekordu	z bazy *
				 *---------------------------*/
				try {
					Object dbEntity = find(entity, false);
					if (dbEntity == null) { // jest to nowy obiekt - nie ma go w
						// bazie
						return true;
					}
					dbDate = (Date) dbEntity.getClass().getMethod(dategetter.getName()).invoke(dbEntity);
					// nowy obiekt
					if (dbDate == null) {
						return true;
					}
				} catch (Exception e) {
					e.printStackTrace();
				}

				/*---------------------------*
				 * Dane rekordu	do zapisania *
				 *---------------------------*/
				try {
					newDate = (Date) dategetter.invoke(entity, new Object[0]);
				} catch (Exception e) {
					e.printStackTrace();
				}

				/*----------------*
				 * Por�wnanie dat *
				 *----------------*/

				if (newDate != null && !newDate.equals(dbDate)) {
					return false;
				} else {
					result = true;
				}

			}
		}

		return result;
	}
	
	public static String getPrefixForDto(Class dto) {
		String prefix = "";
		Method[] methods = dto.getMethods();
		for (int iMethod = 0; iMethod < methods.length; iMethod++) {
			Method method = methods[iMethod];
			Matcher matcher = pattern.matcher(method.getName());
			if (matcher.matches()) {
				prefix = method.getName().substring(PREFIX_BEGIN_INDEX,PREFIX_END_INDEX);
				break;
			}
		}
		return prefix;
	}
	
	public static Long getDtoPK(Object dto) {
		Object ret = getDtoValue("_id", dto);
		if (ret == null) {
			return null;
		}
		return (Long) ret;
	}
	
	public static Object getDtoValue(String suffix, Object dto) {
		Class dtoClass = dto.getClass();
		String getMethodName = getGetterMethod(dtoClass, suffix);
		Class[] paramTypes = null;
		Method getterMethod = null;
		try {
			getterMethod = dtoClass.getMethod(getMethodName, paramTypes);
		} catch (SecurityException e) {
		} catch (NoSuchMethodException e) {
		}
		Object[] param = null;
		Object ret = null;
		try {
			ret = getterMethod.invoke(dto, param);
		} catch (IllegalArgumentException e) {
		} catch (IllegalAccessException e) {
		} catch (InvocationTargetException e) {
		}
		return ret;
	}
	
	public static String getSimpleClassName(Class clazz) {
		return clazz.getName().substring(clazz.getPackage().getName().toString().length() + 1);
	}
	
	private static String getGetterMethod(Class dto, String suffix) {
		return "get" + getPrefixForDto(dto)  + suffix;
	}

	public Object findAndLock(Object entity) {
		// TODO Auto-generated method stub
		return null;
	}

	public void unLockById(Long id) {
		// TODO Auto-generated method stub
		
	}

}
